/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package analisadorSemantico;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import modelo.Constante;
import modelo.ErroSemantico;
import modelo.Funcao;
import modelo.TipoIdentificador;
import modelo.Token;
import modelo.Variavel;
import modelo.IndentificadorJaDeclarado;
import modelo.IdentificadorNaoEncontrada;
import modelo.Procedimento;
import modelo.Programa;
import modelo.tipos.TipoVariavel;

/**
 *
 * @author DEP
 */
public class Escopo {

    private Escopo pai;
    private TabelaDeSimbolos simbolos;
    private String nome;

    public String getNome() {
        return nome;
    }
    
    public Map<String, TipoIdentificador> getSimbolos(){
        return simbolos.getSimbolos();
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public Escopo(Escopo pai, String nome) {
        this.pai = pai;
        this.simbolos = new TabelaDeSimbolos();
        this.nome = nome;
    }

    public Escopo getPai() {
        return pai;
    }

    public TipoIdentificador getIndentificador(String identificador, int linha) throws IdentificadorNaoEncontrada {
        TipoIdentificador procurada = simbolos.get(identificador);

        if (procurada == null) {
            if (pai == null) {
                throw new IdentificadorNaoEncontrada(identificador, linha, procurada);
            } else {
                procurada = pai.getIndentificador(identificador, linha);
            }
        }
        return procurada;
    }

    public void addPrograma(String identificador, int linha) throws IndentificadorJaDeclarado {
        if (simbolos.foiDeclarada(identificador)) {
            throw new IndentificadorJaDeclarado(identificador, linha, new Programa());
        } else {
            simbolos.criarPrograma(identificador, this.nome, linha);
        }
    }

    public void addProcedimento(Procedimento procedimento) throws IndentificadorJaDeclarado {
        if (simbolos.foiDeclarada(procedimento.getNome())) {
            throw new IndentificadorJaDeclarado(procedimento.getNome(), procedimento.getLinha(), new Procedimento());
        } else {
            simbolos.criarProcedimento(procedimento,nome);
        }
    }

    public void addfuncao(Funcao funcao) throws IndentificadorJaDeclarado {
        if (simbolos.foiDeclarada(funcao.getNome())) {
            throw new IndentificadorJaDeclarado(funcao.getNome(), funcao.getLinha(), new Funcao());
        } else {
            simbolos.criarProcedimento(funcao,nome);
        }
    }

    public void addVariavel(String identificador, TipoVariavel tipo, int linha) throws IndentificadorJaDeclarado {
        if (simbolos.foiDeclarada(identificador)) {
            throw new IndentificadorJaDeclarado(identificador, linha, new Variavel());
        } else {
            simbolos.criarVariavel(identificador, tipo, nome, linha);
        }
    }

    public List<ErroSemantico> addVariaveis(Set<Token> s, TipoVariavel t, int linha) throws IndentificadorJaDeclarado, ErroSemantico {
        List<ErroSemantico> erros = new ArrayList<>();
        if (simbolos.foramDeclaradas(s)) {
            for (Token token : s) {
                if (simbolos.foiDeclarada(token.getToken())) {
                    erros.add(new IndentificadorJaDeclarado(token.getToken(), token.getLinha(), new Variavel()));
                }
            }
            return erros;
        } else {
            simbolos.criarTodasVariaveis(s, t, nome, linha);
        }
        return null;
    }

    public void addConstante(String identificador, TipoVariavel tipo, int linha) throws IndentificadorJaDeclarado {
        if (simbolos.foiDeclarada(identificador)) {
            throw new IndentificadorJaDeclarado(identificador, linha, new Constante());
        } else {
            simbolos.criarConstante(identificador, tipo,nome, linha);
        }
    }

}
